﻿using System;
using System.IO;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Xml;
using System.Xml.Schema;
using MSDASC;
using uTILLIty.ChartBuilder.Core.Configuration;
using uTILLIty.ChartBuilder.Core.Extensions;
using uTILLIty.ChartBuilder.Designer.Properties;

namespace uTILLIty.ChartBuilder.Designer
{
	public class ChartDesignerController
	{
		private readonly Core.ChartBuilder _chartBuilder;
		private string _loadedFileName;
		private bool _dataLoaded;

		public ChartDesigner ChartDesignerForm { get; set; }
		public OpenFileDialog OpenFileDialog { get; set; }
		public SaveFileDialog SaveFileDialog { get; set; }
		public Chart Chart { get; set; }
		public BindingSource ConfigBindingSource { get; set; }
		public ToolStripStatusLabel StatusLabel { get; set; }

		protected ChartConfiguration CurrentConfiguration
		{
			get { return (ChartConfiguration)ConfigBindingSource.DataSource; }
		}

		public ChartDesignerController()
		{
			_chartBuilder = new Core.ChartBuilder();
		}

		public void Initialize(ChartDesigner chartDesignerForm, OpenFileDialog openFileDialog, SaveFileDialog saveFileDialog, Chart chart, BindingSource configBindingSource,
			ToolStripStatusLabel statusLabel)
		{
			ChartDesignerForm = chartDesignerForm;
			OpenFileDialog = openFileDialog;
			SaveFileDialog = saveFileDialog;
			Chart = chart;
			ConfigBindingSource = configBindingSource;
			StatusLabel = statusLabel;
		}

		public void BuildConnectionString()
		{
			string connString = CurrentConfiguration.DataSource.ConnectionString;
			try
			{
				var link = new DataLinks();
				ADODB.Connection con;
				if (string.IsNullOrWhiteSpace(connString))
				{
					con = link.PromptNew();
					if (con != null)
						connString = con.ConnectionString;
				}
				else
				{
					con = new ADODB.Connection {ConnectionString = connString};
					object con2 = con;
					if (link.PromptEdit(ref con2))
						connString = con.ConnectionString;
				}
				CurrentConfiguration.DataSource.ConnectionString = connString;
				ConfigBindingSource.ResetCurrentItem();
			}
			catch (Exception ex)
			{
				var msg = string.Format(Resources.ConnStringBuilderLoadError, ex.Message);
				DisplayError(msg);
			}
		}

		public void CreateNewChartConfiguration()
		{
			var config = new ChartConfiguration();
		    _dataLoaded = false;
		    _loadedFileName = null;
            ChartDesignerForm.Text = Program.BuildFormTitle(_loadedFileName);
            AssignConfig(config);
		}

		public void ReloadDataSource()
		{
			var config = CurrentConfiguration;
			try
			{
				var rowCount = _chartBuilder.FillFromDataSource(config, Chart);
				_dataLoaded = true;
				var status = string.Format(Resources.DataReloaded, rowCount);
				DisplayStatus(status);
			}
			catch (Exception ex)
			{
				var msg = string.Format(Resources.ErrorLoadingConfiguration, ex.Message);
				DisplayError(msg);
			}
		}


		protected virtual void DisplayStatus(string status)
		{
			if (ChartDesignerForm.InvokeRequired)
			{
				ChartDesignerForm.Invoke(new Action<string>(DisplayError), status);
				return;
			}
			StatusLabel.Text = string.Format("{0:HH:mm} {1}", DateTime.Now, status);
		}

		protected virtual void DisplayError(string msg)
		{
			if (ChartDesignerForm.InvokeRequired)
			{
				ChartDesignerForm.Invoke(new Action<string>(DisplayError), msg);
				return;
			}

			MessageBox.Show(ChartDesignerForm, msg, Resources.ErrorDialog, MessageBoxButtons.OK, MessageBoxIcon.Error);
		}

		private bool AssignConfig(ChartConfiguration config)
		{
			try
			{
				Chart.DataSource = null;
				Chart.Series.Clear();
				Chart.Legends.Clear();
				Chart.Annotations.Clear();
				Chart.ChartAreas.Clear();
				Chart.Serializer.Reset();
				if (!string.IsNullOrWhiteSpace(config.DataSource.ConnectionString))
					_chartBuilder.PrepareChart(config, Chart);
			}
			catch (Exception ex)
			{
				var msg = string.Format(Resources.ErrorLoadingConfiguration, ex.Message);
				DisplayError(msg);
				return false;
			}
			ConfigBindingSource.DataSource = config;
			return true;
		}

		private ChartConfiguration LoadConfiguration(string fileName)
		{
			try
			{
				using (var configData = File.OpenRead(fileName))
				{
					XmlSchemaSet schemas = Core.ChartBuilder.GetSchemas();
					var config = ObjectExtensions.Load<ChartConfiguration>(configData, schemas);
					//config.DataSource.SqlCommand = config.DataSource.SqlCommand.Trim();
					return config;
				}
			}
			catch (Exception ex)
			{
				var msg = string.Format(Resources.ErrorLoadingConfiguration, ex.Message);
				DisplayError(msg);
				return null;
			}
		}

		public void ReassignChartDimensionsFromConfig()
		{
			Chart.Width = CurrentConfiguration.Width;
			Chart.Height = CurrentConfiguration.Height;
		}

		public void ShowAboutDialog()
		{
			new AboutChartDesigner().ShowDialog(ChartDesignerForm);
		}

		public bool SaveConfiguration(bool saveAs)
		{
			var fileName = _loadedFileName;
			if (saveAs || string.IsNullOrWhiteSpace(fileName))
			{
				var result = SaveFileDialog.ShowDialog();
				switch (result)
				{
					case DialogResult.Yes:
					case DialogResult.OK:
						fileName = SaveFileDialog.FileName;
						break;
					//case DialogResult.None:
					//case DialogResult.Cancel:
					//case DialogResult.Abort:
					//case DialogResult.Retry:
					//case DialogResult.Ignore:
					//case DialogResult.No:
					default:
						return false;
				}
			}

			using (var writer = new StringWriter())
			{
				Chart.Serializer.Content = SerializationContents.All;
				Chart.Serializer.Format = SerializationFormat.Xml;
				Chart.Serializer.IsTemplateMode = true;
				foreach (var s in Chart.Series)
					s.Points.Clear();

				Chart.Serializer.Save(writer);
				writer.Flush();
				var xml = new XmlDocument();
				xml.LoadXml(writer.GetStringBuilder().ToString());
				CurrentConfiguration.Design = xml.DocumentElement;
			}

			using (var stream = File.Open(fileName, FileMode.Truncate))
			{
				CurrentConfiguration.XmlSerialize(stream);
			}

			_loadedFileName = fileName;
			if (_dataLoaded)
				ReloadDataSource();

			var status = string.Format(Resources.FileSaved, fileName);
			DisplayStatus(status);

			return true;
		}

		public void OpenExistingConfiguration()
		{
			var result = OpenFileDialog.ShowDialog();
			switch (result)
			{
				case DialogResult.Yes:
				case DialogResult.OK:
					_dataLoaded = false;
					var config = LoadConfiguration(OpenFileDialog.FileName);
					if (config != null && AssignConfig(config))
						_loadedFileName = OpenFileDialog.FileName;
					ChartDesignerForm.Text = Program.BuildFormTitle(_loadedFileName);

					var status = string.Format(Resources.FileSaved, _loadedFileName);
					DisplayStatus(status);

					break;
				//case DialogResult.None:
				//case DialogResult.Cancel:
				//case DialogResult.Abort:
				//case DialogResult.Retry:
				//case DialogResult.Ignore:
				//case DialogResult.No:
				default:
					return;
			}
		}

		public void ExitApplication()
		{
			Application.Exit();
		}
	}
}